home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / Players / PlayDMO / PlayDMODlg.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-09  |  30.6 KB  |  1,140 lines

  1. //------------------------------------------------------------------------------
  2. // File: PlayDMODlg.cpp
  3. //
  4. // Desc: DirectShow sample code - Implementation for CPlayDMODlg
  5. //
  6. // Copyright (c) 2000-2001 Microsoft Corporation.  All rights reserved.
  7. //------------------------------------------------------------------------------
  8.  
  9. #include "stdafx.h"
  10. #include "PlayDMO.h"
  11. #include "PlayDMODlg.h"
  12.  
  13. #include <mtype.h>
  14.  
  15. #define DEFAULT_FILENAME    TEXT("c:\\")
  16.  
  17. #ifdef _DEBUG
  18. #define new DEBUG_NEW
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. /////////////////////////////////////////////////////////////////////////////
  24. // CAboutDlg dialog used for App About
  25.  
  26. class CAboutDlg : public CDialog
  27. {
  28. public:
  29.     CAboutDlg();
  30.  
  31. // Dialog Data
  32.     //{{AFX_DATA(CAboutDlg)
  33.     enum { IDD = IDD_ABOUTBOX };
  34.     //}}AFX_DATA
  35.  
  36.     // ClassWizard generated virtual function overrides
  37.     //{{AFX_VIRTUAL(CAboutDlg)
  38.     protected:
  39.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
  40.     //}}AFX_VIRTUAL
  41.  
  42. // Implementation
  43. protected:
  44.     //{{AFX_MSG(CAboutDlg)
  45.     //}}AFX_MSG
  46.     DECLARE_MESSAGE_MAP()
  47. };
  48.  
  49. CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
  50. {
  51.     //{{AFX_DATA_INIT(CAboutDlg)
  52.     //}}AFX_DATA_INIT
  53. }
  54.  
  55. void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  56. {
  57.     CDialog::DoDataExchange(pDX);
  58.     //{{AFX_DATA_MAP(CAboutDlg)
  59.     //}}AFX_DATA_MAP
  60. }
  61.  
  62. BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
  63.     //{{AFX_MSG_MAP(CAboutDlg)
  64.         // No message handlers
  65.     //}}AFX_MSG_MAP
  66. END_MESSAGE_MAP()
  67.  
  68. /////////////////////////////////////////////////////////////////////////////
  69. // CPlayDMODlg dialog
  70.  
  71. CPlayDMODlg::CPlayDMODlg(CWnd* pParent /*=NULL*/)
  72.     : CDialog(CPlayDMODlg::IDD, pParent), m_pVW(0), m_pGB(0), m_pMC(0)
  73. {
  74.     //{{AFX_DATA_INIT(CPlayDMODlg)
  75.     //}}AFX_DATA_INIT
  76.     // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
  77.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  78. }
  79.  
  80. void CPlayDMODlg::DoDataExchange(CDataExchange* pDX)
  81. {
  82.     CDialog::DoDataExchange(pDX);
  83.     //{{AFX_DATA_MAP(CPlayDMODlg)
  84.     DDX_Control(pDX, IDC_BUTTON_PROPPAGE, m_btnProperties);
  85.     DDX_Control(pDX, IDC_STATIC_STATUS, m_strStatus);
  86.     DDX_Control(pDX, IDC_STATIC_OUT_MINBUFFERSIZE, m_nOutBufferSize);
  87.     DDX_Control(pDX, IDC_STATIC_OUT_ALIGNMENT, m_nOutAlignment);
  88.     DDX_Control(pDX, IDC_STATIC_MAXLATENCY, m_nMaxLatency);
  89.     DDX_Control(pDX, IDC_STATIC_IN_MINBUFFERSIZE, m_nInBufferSize);
  90.     DDX_Control(pDX, IDC_STATIC_IN_MAXLOOKAHEAD, m_nInLookahead);
  91.     DDX_Control(pDX, IDC_STATIC_IN_ALIGNMENT, m_nInAlignment);
  92.     DDX_Control(pDX, IDC_LIST_FILTERS, m_ListFilters);
  93.     DDX_Control(pDX, IDC_LIST_FILTER_OUTPUTS, m_ListFilterOutputs);
  94.     DDX_Control(pDX, IDC_LIST_FILTER_INPUTS, m_ListFilterInputs);
  95.     DDX_Control(pDX, IDC_LIST_AUDIO_DMOS, m_ListAudioDMO);
  96.     DDX_Control(pDX, IDC_EDIT_FILENAME, m_StrFilename);
  97.     DDX_Control(pDX, IDC_BUTTON_STOP, m_btnStop);
  98.     DDX_Control(pDX, IDC_BUTTON_PLAY, m_btnPlay);
  99.     DDX_Control(pDX, IDC_BUTTON_PAUSE, m_btnPause);
  100.     DDX_Control(pDX, IDC_SCREEN, m_Screen);
  101.     //}}AFX_DATA_MAP
  102. }
  103.  
  104. BEGIN_MESSAGE_MAP(CPlayDMODlg, CDialog)
  105.     //{{AFX_MSG_MAP(CPlayDMODlg)
  106.     ON_WM_ERASEBKGND()
  107.     ON_WM_SYSCOMMAND()
  108.     ON_WM_PAINT()
  109.     ON_WM_QUERYDRAGICON()
  110.     ON_WM_CLOSE()
  111.     ON_WM_DESTROY()
  112.     ON_BN_CLICKED(IDC_BUTTON_PLAY, OnButtonPlay)
  113.     ON_BN_CLICKED(IDC_BUTTON_PAUSE, OnButtonPause)
  114.     ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
  115.     ON_BN_CLICKED(IDC_BUTTON_FILE, OnButtonFile)
  116.     ON_LBN_SELCHANGE(IDC_LIST_FILTERS, OnSelchangeListFilters)
  117.     ON_BN_CLICKED(IDC_BUTTON_ADD_DMO, OnButtonAddDmo)
  118.     ON_BN_CLICKED(IDC_BUTTON_CLEAR, OnButtonClear)
  119.     ON_BN_CLICKED(IDC_BUTTON_PROPPAGE, OnButtonProppage)
  120.     ON_LBN_DBLCLK(IDC_LIST_FILTERS, OnDblclkListFilters)
  121.     //}}AFX_MSG_MAP
  122. END_MESSAGE_MAP()
  123.  
  124. /////////////////////////////////////////////////////////////////////////////
  125. // CPlayDMODlg message handlers
  126.  
  127. void CPlayDMODlg::OnSysCommand(UINT nID, LPARAM lParam)
  128. {
  129.     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
  130.     {
  131.         CAboutDlg dlgAbout;
  132.         dlgAbout.DoModal();
  133.     }
  134.     else
  135.     {
  136.         CDialog::OnSysCommand(nID, lParam);
  137.     }
  138. }
  139.  
  140. // If you add a minimize button to your dialog, you will need the code below
  141. //  to draw the icon.  For MFC applications using the document/view model,
  142. //  this is automatically done for you by the framework.
  143.  
  144. void CPlayDMODlg::OnPaint() 
  145. {
  146.     if (IsIconic())
  147.     {
  148.         CPaintDC dc(this); // device context for painting
  149.  
  150.         SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
  151.  
  152.         // Center icon in client rectangle
  153.         int cxIcon = GetSystemMetrics(SM_CXICON);
  154.         int cyIcon = GetSystemMetrics(SM_CYICON);
  155.         CRect rect;
  156.         GetClientRect(&rect);
  157.         int x = (rect.Width() - cxIcon + 1) / 2;
  158.         int y = (rect.Height() - cyIcon + 1) / 2;
  159.  
  160.         // Draw the icon
  161.         dc.DrawIcon(x, y, m_hIcon);
  162.     }
  163.     else
  164.     {
  165.         CDialog::OnPaint();
  166.     }
  167. }
  168.  
  169. // The system calls this to obtain the cursor to display while the user drags
  170. //  the minimized window.
  171. HCURSOR CPlayDMODlg::OnQueryDragIcon()
  172. {
  173.     return (HCURSOR) m_hIcon;
  174. }
  175.  
  176.  
  177.  
  178. BOOL CPlayDMODlg::OnInitDialog()
  179. {
  180.     CDialog::OnInitDialog();
  181.  
  182.     // Add "About..." menu item to system menu.
  183.  
  184.     // IDM_ABOUTBOX must be in the system command range.
  185.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  186.     ASSERT(IDM_ABOUTBOX < 0xF000);
  187.  
  188.     CMenu* pSysMenu = GetSystemMenu(FALSE);
  189.     if (pSysMenu != NULL)
  190.     {
  191.         CString strAboutMenu;
  192.         strAboutMenu.LoadString(IDS_ABOUTBOX);
  193.         if (!strAboutMenu.IsEmpty())
  194.         {
  195.             pSysMenu->AppendMenu(MF_SEPARATOR);
  196.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  197.         }
  198.     }
  199.  
  200.     // Set the icon for this dialog.  The framework does this automatically
  201.     //  when the application's main window is not a dialog
  202.     SetIcon(m_hIcon, TRUE);            // Set big icon
  203.     SetIcon(m_hIcon, FALSE);        // Set small icon
  204.     
  205.     ////////////////////////////////////////////////////////////////////////
  206.     //
  207.     //  DirectShow-specific initialization code
  208.  
  209.     CoInitialize(NULL);
  210.     SetDefaults();
  211.  
  212.     // Initialize DirectShow and query for needed interfaces
  213.     HRESULT hr = InitDirectShow();
  214.     if(FAILED(hr))
  215.     {
  216.         RetailOutput(TEXT("Failed to initialize DirectShow!  hr=0x%x\r\n"), hr);
  217.         return FALSE;
  218.     }
  219.  
  220.     // IMPORTANT
  221.     // Since we're embedding video in a child window of a dialog,
  222.     // we must set the WS_CLIPCHILDREN style to prevent the bounding
  223.     // rectangle from drawing over our video frames.
  224.     //
  225.     // Neglecting to set this style can lead to situations when the video
  226.     // is erased and replaced with black (or the default color of the 
  227.     // bounding rectangle).
  228.     m_Screen.ModifyStyle(0, WS_CLIPCHILDREN);
  229.  
  230.     hr = FillLists();
  231.     if(FAILED(hr))
  232.     {
  233.         RetailOutput(TEXT("Failed to fill DMO list!  hr=0x%x\r\n"), hr);
  234.         return FALSE;
  235.     }
  236.  
  237.     return TRUE;  // return TRUE  unless you set the focus to a control
  238. }
  239.  
  240. void CPlayDMODlg::SetDefaults()
  241. {
  242.     // Zero DirectShow interface pointers (sanity check)
  243.     m_pGB=0;
  244.     m_pMS=0;
  245.     m_pMC=0;
  246.     m_pME=0;
  247.     m_pVW=0;
  248.  
  249.     // Zero DMO list
  250.     for (int i=0; i<MAX_DMOS; i++)
  251.         m_pDMOList[i] = 0;
  252.  
  253.     // Set default values for controls on the dialog
  254.     m_StrFilename.SetWindowText(DEFAULT_FILENAME);
  255.     g_psCurrent = State_Stopped;
  256. }
  257.  
  258.  
  259. HRESULT CPlayDMODlg::FillLists() 
  260. {
  261.     HRESULT hr;
  262.  
  263.     // Enumerate and display the audio DMOs installed in the system
  264.     hr = AddDMOsToList(&DMOCATEGORY_AUDIO_EFFECT, m_ListAudioDMO, TRUE);
  265.     if (FAILED(hr))
  266.         return hr;
  267.  
  268.     // Set internal variables
  269.     m_nLoadedDMOs = 0;
  270.     m_nDMOCount = m_ListAudioDMO.GetCount();
  271.     
  272.     return hr;
  273. }
  274.  
  275. //
  276. //  Displays a text string in a status line near the bottom of the dialog
  277. //
  278. void CPlayDMODlg::Say(LPTSTR szText)
  279. {
  280.     m_strStatus.SetWindowText(szText);
  281. }
  282.  
  283. HRESULT CPlayDMODlg::InitDirectShow(void)
  284. {
  285.     HRESULT hr = S_OK;
  286.  
  287.     m_bAudioOnly = FALSE;
  288.  
  289.     // Get interfaces
  290.     JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, 
  291.                          IID_IGraphBuilder, (void **)&m_pGB));
  292.  
  293.     JIF(m_pGB->QueryInterface(IID_IMediaControl,  (void **)&m_pMC));
  294.     JIF(m_pGB->QueryInterface(IID_IMediaSeeking,  (void **)&m_pMS));
  295.     JIF(m_pGB->QueryInterface(IID_IVideoWindow,   (void **)&m_pVW));
  296.     JIF(m_pGB->QueryInterface(IID_IMediaEventEx,  (void **)&m_pME));
  297.  
  298.     return S_OK;
  299.  
  300. CLEANUP:
  301.     FreeDirectShow();
  302.     return(hr);
  303. }
  304.  
  305. HRESULT CPlayDMODlg::FreeDirectShow(void)
  306. {
  307.     HRESULT hr=S_OK;
  308.  
  309.     StopMedia();
  310.  
  311.     // Disable event callbacks
  312.     if (m_pME)
  313.         hr = m_pME->SetNotifyWindow((OAHWND)NULL, 0, 0);
  314.  
  315.     // Hide video window and remove owner.  This is not necessary here,
  316.     // since we are about to destroy the filter graph, but it is included
  317.     // for demonstration purposes.  Remember to hide the video window and
  318.     // clear its owner when destroying a window that plays video.
  319.     if(m_pVW)
  320.     {
  321.         hr = m_pVW->put_Visible(OAFALSE);
  322.         hr = m_pVW->put_Owner(NULL);
  323.     }
  324.  
  325. #ifdef DEBUG
  326.     RemoveGraphFromRot(m_dwRegister);
  327. #endif
  328.  
  329.     RemoveDMOsFromGraph();
  330.  
  331.     SAFE_RELEASE(m_pMC);
  332.     SAFE_RELEASE(m_pMS);
  333.     SAFE_RELEASE(m_pVW);
  334.     SAFE_RELEASE(m_pME);
  335.     SAFE_RELEASE(m_pGB);
  336.  
  337.     ClearLists();
  338.     return hr;
  339. }
  340.  
  341. void CPlayDMODlg::ResetDirectShow(void)
  342. {
  343.     // Destroy the current filter graph its filters.
  344.     FreeDirectShow();
  345.  
  346.     // Reinitialize graph builder and query for interfaces
  347.     InitDirectShow();
  348. }
  349.  
  350. void CPlayDMODlg::ClearAllocatedLists()
  351. {
  352.     // Clear the lists and delete the allocated CLSID bytes
  353.     ClearFilterListWithCLSID(m_ListAudioDMO);
  354. }
  355.  
  356. void CPlayDMODlg::ClearLists()
  357. {
  358.     // Clear the lists that don't contain extra data
  359.     m_ListFilters.ResetContent();
  360.     m_ListFilterInputs.ResetContent();
  361.     m_ListFilterOutputs.ResetContent();
  362. }
  363.  
  364. void CPlayDMODlg::OnClose() 
  365. {
  366.     // Release DirectShow interfaces
  367.     StopMedia();
  368.     FreeDirectShow();
  369.     ClearAllocatedLists();
  370.  
  371.     // Release COM
  372.     CoUninitialize();
  373.  
  374.     CDialog::OnClose();
  375. }
  376.  
  377. void CPlayDMODlg::OnDestroy() 
  378. {
  379.     // Release DirectShow interfaces
  380.     FreeDirectShow();
  381.     ClearAllocatedLists();
  382.  
  383.     CDialog::OnDestroy();
  384. }
  385.  
  386. void CPlayDMODlg::OnButtonPlay() 
  387. {
  388.     if (g_psCurrent == State_Paused)
  389.     {
  390.         RunMedia();
  391.     }
  392.     else
  393.     {
  394.         if (SUCCEEDED(OnSelectFile()))
  395.         {
  396.             // Add any selected DMOs to the graph
  397.             OnButtonAddDmo();
  398.  
  399.             // Disconnect audio renderer and insert DMOs
  400.             if (m_nLoadedDMOs != 0)
  401.             {
  402.                 if (FAILED(ConnectDMOsToRenderer()))
  403.                 {
  404.                     MessageBeep(0);
  405.                     EnableButtons(FALSE);
  406.                     return;
  407.                 }
  408.             }
  409.  
  410.             EnableButtons(FALSE);
  411.               RunMedia();
  412.         }
  413.         else
  414.         {
  415.             MessageBox(TEXT("Please enter a valid media file name."), 
  416.                        TEXT("Error opening media file!"));
  417.             return;
  418.         }
  419.     }
  420.  
  421.     Say(TEXT("Running"));
  422. }
  423.  
  424. void CPlayDMODlg::OnButtonPause() 
  425. {
  426.     PauseMedia();
  427.     Say(TEXT("Paused"));
  428. }
  429.  
  430. void CPlayDMODlg::OnButtonStop() 
  431. {
  432.     HRESULT hr;
  433.  
  434.     // Stop playback immediately with IMediaControl::Stop().
  435.     StopMedia();
  436.     EnableButtons(TRUE);
  437.  
  438.     // Reset to beginning of media clip
  439.     LONGLONG pos=0;
  440.     hr = m_pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
  441.                            NULL, AM_SEEKING_NoPositioning);
  442.     if (FAILED(hr))
  443.     {
  444.         RetailOutput(TEXT("Failed to seek to beginning of media!  hr=0x%x\r\n"), hr);
  445.     }
  446.   
  447.     // Display the first frame of the media clip, if it contains video.
  448.     // StopWhenReady() pauses all filters internally (which allows the video
  449.     // renderer to queue and display the first video frame), after which
  450.     // it sets the filters to the stopped state.  This enables easy preview
  451.     // of the video's poster frame.
  452.     hr = m_pMC->StopWhenReady();
  453.     if (FAILED(hr))
  454.     {
  455.         RetailOutput(TEXT("Failed in StopWhenReady!  hr=0x%x\r\n"), hr);
  456.     }
  457.  
  458.     Say(TEXT("Stopped"));
  459. }
  460.  
  461. void CPlayDMODlg::OnButtonFile() 
  462. {
  463.     CFileDialog dlgFile(TRUE);
  464.     CString title;
  465.     CString strFilter, strDefault, strFilename;
  466.  
  467.     VERIFY(title.LoadString(AFX_IDS_OPENFILE));
  468.  
  469.     // Initialize the file extensions and descriptions
  470.     strFilter += "Media Files (*.avi, *.mpg, *.wav, *.mid)";
  471.     strFilter += (TCHAR)'\0';
  472.     strFilter += _T("*.avi;*.mpg;*.wav;*.mid");
  473.     strFilter += (TCHAR)'\0';
  474.     dlgFile.m_ofn.nMaxCustFilter++;
  475.  
  476.     CString allFilter;
  477.     VERIFY(allFilter.LoadString(AFX_IDS_ALLFILTER));
  478.  
  479.     // Append the "*.*" all files filter
  480.     strFilter += allFilter;
  481.     strFilter += (TCHAR)'\0';     // next string
  482.     strFilter += _T("*.*");
  483.     strFilter += (TCHAR)'\0\0';   // last string
  484.     dlgFile.m_ofn.nMaxCustFilter++;
  485.  
  486.     dlgFile.m_ofn.lpstrFilter = strFilter;
  487.     dlgFile.m_ofn.lpstrTitle = title;
  488.     dlgFile.m_ofn.lpstrFile = strFilename.GetBuffer(_MAX_PATH);
  489.  
  490.     // Display the file open dialog
  491.     INT_PTR nResult = dlgFile.DoModal();
  492.  
  493.     // If a file was selected, update the main dialog
  494.     if (nResult == IDOK)
  495.     {
  496.         m_StrFilename.SetWindowText(strFilename);
  497.  
  498.         // Render this file and show the first video frame, if present
  499.         OnSelectFile();
  500.     }
  501.  
  502.     strFilename.ReleaseBuffer();
  503. }
  504.  
  505.  
  506. void CPlayDMODlg::OnButtonAddDmo() 
  507. {
  508.     // Release any currently loaded DMOs
  509.     RemoveDMOsFromGraph();
  510.  
  511.     // Add the currently selected DMOs to the graph
  512.     AddDMOsToGraph();
  513.  
  514.     // Update the graph filter display to show rendered graph
  515.     AddGraphFiltersToList(m_pGB, m_ListFilters);
  516. }
  517.  
  518. void CPlayDMODlg::OnButtonClear() 
  519. {
  520.     // Release any currently loaded DMOs
  521.     RemoveDMOsFromGraph();
  522.  
  523.     // Clear the list of active DMOs
  524.     m_ListAudioDMO.SelItemRange(FALSE, 0, m_nDMOCount);
  525.  
  526.     // Update the graph filter display to show rendered graph
  527.     AddGraphFiltersToList(m_pGB, m_ListFilters);
  528. }
  529.  
  530. HRESULT CPlayDMODlg::RemoveDMOsFromGraph(void)
  531. {
  532.     HRESULT hr=S_OK;
  533.  
  534.     // Remove and release each loaded DMO
  535.     for (int i=0; i < m_nLoadedDMOs; i++)
  536.     {
  537.         if (m_pDMOList[i])
  538.         {
  539.             // Remove filter from graph.
  540.             hr = m_pGB->RemoveFilter(m_pDMOList[i]);
  541.  
  542.             // Since we're not holding a reference to the filter, 
  543.             // there's no need to Release() it, but do clear the variable.
  544.             m_pDMOList[i]=0;
  545.         }
  546.     }
  547.  
  548.     m_nLoadedDMOs = 0;
  549.     return hr;
  550. }
  551.  
  552. HRESULT CPlayDMODlg::AddDMOsToGraph(void)
  553. {
  554.     USES_CONVERSION;
  555.     HRESULT hr=S_OK;
  556.     IBaseFilter *pDMOFilter=0;
  557.     IDMOWrapperFilter *pWrap;
  558.     CLSID *pStoredCLSID = NULL;
  559.     int rnItems[MAX_DMOS];
  560.     WCHAR wszDMOName[64];
  561.     TCHAR szItem[64];
  562.  
  563.     // Clear status
  564.     m_nLoadedDMOs = 0;
  565.  
  566.     // Get a list of the DMO entries selected in the multiple-select listbox
  567.     int nSelected = m_ListAudioDMO.GetSelItems(MAX_DMOS, rnItems);
  568.  
  569.     // Load each selected DMO and add it to the graph
  570.     for (int i=0; i < nSelected; i++)
  571.     {
  572.         // Read this DMO's CLSID from the list box
  573.         pStoredCLSID = (CLSID *) m_ListAudioDMO.GetItemDataPtr(rnItems[i]);
  574.  
  575.         // Create the DMO Wrapper filter.
  576.         hr = CoCreateInstance(CLSID_DMOWrapperFilter, NULL, CLSCTX_INPROC, 
  577.                               IID_IBaseFilter, (void **)&pDMOFilter);
  578.         if (FAILED(hr))
  579.             continue;
  580.  
  581.         // Get its DMOWrapperFilter interface so that it can be added to
  582.         // the DirectShow filter graph
  583.         hr = pDMOFilter->QueryInterface(IID_IDMOWrapperFilter, (void **)&pWrap);
  584.  
  585.         if (SUCCEEDED(hr)) 
  586.         {     
  587.             // Initialize the wrapper filter with our DMO's CLSID and category
  588.             hr = pWrap->Init(*pStoredCLSID, DMOCATEGORY_AUDIO_EFFECT); 
  589.             if (FAILED(hr))
  590.             {
  591.                 pWrap->Release();
  592.                 pDMOFilter->Release();
  593.                 continue;
  594.             }
  595.  
  596.             pWrap->Release();
  597.  
  598.             // Read the DMO's name and convert to a wide string
  599.             m_ListAudioDMO.GetText(rnItems[i], szItem);
  600.             wcscpy(wszDMOName, T2W(szItem));
  601.  
  602.             // Add the DMO to the graph
  603.             hr = m_pGB->AddFilter(pDMOFilter, wszDMOName);
  604.             if (FAILED(hr))
  605.                 return hr;
  606.  
  607.             // If this filter was added to the graph, save its reference
  608.             // and increment the count of loaded DMOs
  609.             m_pDMOList[i] = pDMOFilter;
  610.             m_nLoadedDMOs++;
  611.         }
  612.  
  613.         pDMOFilter->Release();
  614.     }
  615.  
  616.     return hr;
  617. }
  618.  
  619.  
  620. void CPlayDMODlg::OnSelchangeListFilters() 
  621. {
  622.     IBaseFilter *pFilter = NULL;
  623.     TCHAR szNameToFind[128];
  624.  
  625.     // Use a helper function to display the filter's pins in listboxes
  626.     AddFilterPinsToLists(m_pGB, m_ListFilters, m_ListFilterInputs, m_ListFilterOutputs);
  627.  
  628.     // Read the current filter name from the list box
  629.     m_ListFilters.GetText(m_ListFilters.GetCurSel(), szNameToFind);
  630.  
  631.     // Read the current list box name and find it in the graph.
  632.     // Display DMO-specific information if present in the graph.
  633.     pFilter = FindFilterFromName(m_pGB, szNameToFind);
  634.     if (pFilter)
  635.     {
  636.         HRESULT hr;
  637.         IMediaObject *pDMO=NULL;
  638.  
  639.         // Find out if this filter supports a property page
  640.         if (SupportsPropertyPage(pFilter))
  641.             m_btnProperties.EnableWindow(TRUE);
  642.         else
  643.             m_btnProperties.EnableWindow(FALSE);
  644.  
  645.         // If this is a DMO, it will support IMediaObject, so show more info.
  646.         hr = pFilter->QueryInterface(IID_IMediaObject, (void**) &pDMO);
  647.  
  648.         // Show information or default values
  649.         ShowInputBufferInfo(pDMO, 0);
  650.         ShowOutputBufferInfo(pDMO, 0);
  651.  
  652.         if (SUCCEEDED(hr))
  653.             pDMO->Release();
  654.  
  655.         pFilter->Release();
  656.     }
  657. }
  658.  
  659.  
  660. HRESULT CPlayDMODlg::OnSelectFile() 
  661. {
  662.     HRESULT hr;
  663.     TCHAR szFilename[MAX_PATH];
  664.  
  665.     // Read file name from list box
  666.     m_StrFilename.GetWindowText(szFilename, MAX_PATH);
  667.  
  668.     // First release any existing interfaces
  669.     ResetDirectShow();
  670.  
  671.     // Clear filter/pin/event information listboxes
  672.     m_ListFilters.ResetContent();
  673.     m_ListFilterInputs.ResetContent();
  674.     m_ListFilterOutputs.ResetContent();
  675.  
  676.     // Load the selected media file
  677.     hr = PrepareMedia(szFilename);
  678.     if (FAILED(hr))
  679.     {
  680.         MessageBeep(0);
  681.         return hr;
  682.     }
  683.     else
  684.     {
  685.         m_btnPlay.EnableWindow(TRUE);
  686.     }
  687.  
  688.     // Enumerate and display filters in graph
  689.     hr = AddGraphFiltersToList(m_pGB, m_ListFilters);
  690.  
  691.     // Select the first filter in the list to display pin info
  692.     m_ListFilters.SetCurSel(0);
  693.     OnSelchangeListFilters();
  694.  
  695.     // Cue the first video frame
  696.     m_pMC->StopWhenReady();
  697.     return hr;
  698. }
  699.  
  700.  
  701. HRESULT CPlayDMODlg::PrepareMedia(LPTSTR lpszMovie)
  702. {
  703.     USES_CONVERSION;
  704.     HRESULT hr = S_OK;
  705.  
  706.     Say(TEXT("Loading..."));
  707.  
  708.     // Allow DirectShow to create the FilterGraph for this media file
  709.     hr = m_pGB->RenderFile(T2W(lpszMovie), NULL);
  710.     if (FAILED(hr)) {
  711.         RetailOutput(TEXT("*** Failed(%08lx) in RenderFile(%s)!\r\n"),
  712.                  hr, lpszMovie);
  713.         return hr;
  714.     }
  715.  
  716.     // Add our filter graph to the running object table for debugging
  717. #ifdef DEBUG
  718.     AddGraphToRot(m_pGB, &m_dwRegister);
  719. #endif
  720.  
  721.     // Set the message drain of the video window to point to our main
  722.     // application window.  If this is an audio-only or MIDI file, 
  723.     // then put_MessageDrain will fail.
  724.     hr = m_pVW->put_MessageDrain((OAHWND) m_hWnd);
  725.     if (FAILED(hr))
  726.     {
  727.         m_bAudioOnly = TRUE;
  728.     }
  729.  
  730.     // Have the graph signal events via window callbacks
  731.     hr = m_pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0);
  732.  
  733.     // Configure the video window
  734.     if (!m_bAudioOnly)
  735.     {
  736.         hr = m_pVW->put_Owner((OAHWND) m_Screen.GetSafeHwnd());
  737.         hr = m_pVW->put_WindowStyle(WS_CHILD);
  738.  
  739.         // We'll manually set the video to be visible
  740.         hr = m_pVW->put_Visible(OAFALSE);
  741.  
  742.         // Place video window within the bounding rectangle
  743.         CenterVideo();
  744.  
  745.         // Make the video window visible within the screen window.
  746.         // If this is an audio-only file, then there won't be a video interface.
  747.         hr = m_pVW->put_Visible(OATRUE);
  748.         hr = m_pVW->SetWindowForeground(-1);
  749.     }
  750.  
  751.     Say(TEXT("Ready"));
  752.     return hr;
  753. }
  754.  
  755. void CPlayDMODlg::CenterVideo(void)
  756. {
  757.     LONG width, height;
  758.     HRESULT hr;
  759.  
  760.     if ((m_bAudioOnly) || (!m_pVW))
  761.         return;
  762.  
  763.     // Read coordinates of video container window
  764.     RECT rc;
  765.     m_Screen.GetClientRect(&rc);
  766.     width =  rc.right - rc.left;
  767.     height = rc.bottom - rc.top;
  768.  
  769.     // Ignore the video's original size and stretch to fit bounding rectangle
  770.     hr = m_pVW->SetWindowPosition(rc.left, rc.top, width, height);
  771.     if (FAILED(hr))
  772.     {
  773.         RetailOutput(TEXT("Failed to set window position!  hr=0x%x\r\n"), hr);
  774.         return;
  775.     }
  776. }
  777.  
  778. LRESULT CPlayDMODlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
  779. {
  780.     // Field notifications from the DirectShow filter graph manager
  781.     // and those posted by the application
  782.     switch (message)
  783.     {
  784.         case WM_GRAPHNOTIFY:
  785.             HandleGraphEvent();
  786.             break;
  787.     }
  788.  
  789.     // Pass along this message to the video window, which exists as a child
  790.     // of the m_Screen window.  This method should be used by windows that 
  791.     // make a renderer window a child window. It forwards significant messages 
  792.     // to the child window that the child window would not otherwise receive. 
  793.     if (m_pVW)
  794.     {
  795.         m_pVW->NotifyOwnerMessage((LONG_PTR) m_hWnd, message, wParam, lParam);
  796.     }
  797.  
  798.     return CDialog::WindowProc(message, wParam, lParam);
  799. }
  800.  
  801.  
  802. HRESULT CPlayDMODlg::HandleGraphEvent(void)
  803. {
  804.     LONG evCode, evParam1, evParam2;
  805.     HRESULT hr=S_OK;
  806.  
  807.     // Check that event interface is still valid
  808.     if (!m_pME)
  809.         return S_OK;
  810.     
  811.     // Spin through the events
  812.     while(SUCCEEDED(hr = m_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1, 
  813.                                           (LONG_PTR *) &evParam2, 0)))
  814.     {
  815.         if(EC_COMPLETE == evCode)
  816.         {
  817.             // Since we're looping, reset to beginning and continue playing
  818.             LONGLONG pos=0;
  819.             hr = m_pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
  820.                                      NULL, AM_SEEKING_NoPositioning);
  821.         }
  822.  
  823.         // Free memory associated with this event
  824.         hr = m_pME->FreeEventParams(evCode, evParam1, evParam2);
  825.     }
  826.  
  827.     return hr;
  828. }
  829.  
  830.  
  831. HRESULT CPlayDMODlg::RunMedia()
  832. {
  833.     HRESULT hr=S_OK;
  834.  
  835.     if (!m_pMC)
  836.         return S_OK;
  837.  
  838.     // Start playback
  839.     hr = m_pMC->Run();
  840.     if (FAILED(hr)) {
  841.         RetailOutput(TEXT("\r\n*** Failed(%08lx) in Run()!\r\n"), hr);
  842.         return hr;
  843.     }
  844.  
  845.     // Remember play state
  846.     g_psCurrent = State_Running;
  847.     return hr;
  848. }
  849.  
  850.  
  851. HRESULT CPlayDMODlg::StopMedia()
  852. {
  853.     HRESULT hr=S_OK;
  854.  
  855.     if (!m_pMC)
  856.         return S_OK;
  857.  
  858.     // If we're already stopped, don't check again
  859.     if (g_psCurrent == State_Stopped)
  860.         return hr;
  861.  
  862.     // Stop playback
  863.     hr = m_pMC->Stop();
  864.     if (FAILED(hr)) {
  865.         RetailOutput(TEXT("\r\n*** Failed(%08lx) in Stop()!\r\n"), hr);
  866.         return hr;
  867.     }
  868.  
  869.     // Wait for the stop to propagate to all filters
  870.     OAFilterState fs;
  871.     hr = m_pMC->GetState(500, &fs);
  872.     if (FAILED(hr))
  873.     {
  874.         RetailOutput(TEXT("Failed to read graph state!  hr=0x%x\r\n"), hr);
  875.     }
  876.  
  877.     // Remember play state
  878.     g_psCurrent = State_Stopped;
  879.     return hr;
  880. }
  881.  
  882.  
  883. HRESULT CPlayDMODlg::PauseMedia(void)
  884. {
  885.     HRESULT hr=S_OK;
  886.  
  887.     if (!m_pMC)
  888.         return S_OK;
  889.  
  890.     // Don't pause unless we're in the running state
  891.     if(g_psCurrent != State_Running)
  892.         return S_OK;
  893.  
  894.     // Pause playback
  895.     hr = m_pMC->Pause();
  896.     if (FAILED(hr)) {
  897.         RetailOutput(TEXT("\r\n*** Failed(%08lx) in Pause()!\r\n"), hr);
  898.         return hr;
  899.     }
  900.  
  901.     // Remember play state
  902.     g_psCurrent = State_Paused;
  903.     return hr;
  904. }
  905.  
  906.  
  907. void CPlayDMODlg::OnButtonProppage() 
  908. {
  909.     IBaseFilter *pFilter = NULL;
  910.     TCHAR szNameToFind[128];
  911.  
  912.     // Read the current filter name from the list box
  913.     int nCurSel = m_ListFilters.GetCurSel();
  914.     m_ListFilters.GetText(nCurSel, szNameToFind);
  915.  
  916.     // Find this filter in the graph
  917.     pFilter = FindFilterFromName(m_pGB, szNameToFind);
  918.     if (!pFilter)
  919.         return;
  920.  
  921.     // Show the property page for the selected DMO or filter
  922.     ShowFilterPropertyPage(pFilter, m_hWnd);
  923. }
  924.  
  925. void CPlayDMODlg::OnDblclkListFilters() 
  926. {
  927.     // Show the property page for the selected DMO or filter
  928.     OnButtonProppage();
  929. }
  930.  
  931.  
  932. void CPlayDMODlg::ShowInputBufferInfo(IMediaObject *pDMO, int nSel)
  933. {
  934.     HRESULT hr;
  935.     TCHAR sz[32];
  936.     DWORD dwSize=0, dwLookahead=0, dwAlign=0;
  937.  
  938.     // If the selected item is not a DMO, display default information
  939.     if (!pDMO)
  940.     {
  941.         m_nInBufferSize.SetWindowText(STR_NOTDMO);
  942.         m_nInLookahead.SetWindowText(STR_NOTDMO);
  943.         m_nInAlignment.SetWindowText(STR_NOTDMO);
  944.         m_nMaxLatency.SetWindowText(STR_NOTDMO);
  945.         return;
  946.     }
  947.  
  948.     // Read/display maximum latency
  949.     REFERENCE_TIME reftime=0;
  950.     hr = pDMO->GetInputMaxLatency(nSel, &reftime);
  951.     if (SUCCEEDED(hr))
  952.     {
  953.         DWORD dwLatency = (DWORD) (reftime * 100000);
  954.         wsprintf(sz, TEXT("%ld"), dwLatency);
  955.         m_nMaxLatency.SetWindowText(sz);
  956.     }
  957.     else if (hr == E_NOTIMPL)
  958.         m_nMaxLatency.SetWindowText(TEXT("0"));
  959.     else
  960.         m_nMaxLatency.SetWindowText(STR_UNKNOWN);
  961.  
  962.     // Read/display input buffer size information
  963.     hr = pDMO->GetInputSizeInfo(nSel, &dwSize, &dwLookahead, &dwAlign);
  964.     if (SUCCEEDED(hr))
  965.     {
  966.         wsprintf(sz, TEXT("%ld"), dwSize);
  967.         m_nInBufferSize.SetWindowText(sz);
  968.  
  969.         wsprintf(sz, TEXT("%ld"), dwLookahead);
  970.         m_nInLookahead.SetWindowText(sz);
  971.  
  972.         wsprintf(sz, TEXT("%ld"), dwAlign);
  973.         m_nInAlignment.SetWindowText(sz);
  974.     }
  975.     else
  976.     {
  977.         m_nInBufferSize.SetWindowText(STR_UNKNOWN);
  978.         m_nInLookahead.SetWindowText(STR_UNKNOWN);
  979.         m_nInAlignment.SetWindowText(STR_UNKNOWN);
  980.     }
  981. }
  982.  
  983. void CPlayDMODlg::ShowOutputBufferInfo(IMediaObject *pDMO, int nSel)
  984. {
  985.     HRESULT hr;
  986.     TCHAR sz[32];
  987.     DWORD dwSize=0, dwAlign=0;
  988.  
  989.     // If the selected item is not a DMO, display default information
  990.     if (!pDMO)
  991.     {
  992.         m_nOutBufferSize.SetWindowText(STR_NOTDMO);
  993.         m_nOutAlignment.SetWindowText(STR_NOTDMO);
  994.         return;
  995.     }
  996.  
  997.     // Read/display output buffer size information
  998.     hr = pDMO->GetOutputSizeInfo(nSel, &dwSize, &dwAlign);
  999.  
  1000.     if (SUCCEEDED(hr))
  1001.     {
  1002.         wsprintf(sz, TEXT("%ld"), dwSize);
  1003.         m_nOutBufferSize.SetWindowText(sz);
  1004.  
  1005.         wsprintf(sz, TEXT("%ld"), dwAlign);
  1006.         m_nOutAlignment.SetWindowText(sz);
  1007.     }
  1008.     else
  1009.     {
  1010.         m_nOutBufferSize.SetWindowText(STR_UNKNOWN);
  1011.         m_nOutAlignment.SetWindowText(STR_UNKNOWN);
  1012.     }
  1013. }
  1014.  
  1015.  
  1016. void CPlayDMODlg::EnableButtons(BOOL bEnable)
  1017. {
  1018.     // Enable or disable buttons and other dialog items
  1019.     m_StrFilename.EnableWindow(bEnable);
  1020.     m_ListAudioDMO.EnableWindow(bEnable);
  1021.  
  1022.     GetDlgItem(IDC_BUTTON_ADD_DMO)->EnableWindow(bEnable);
  1023.     GetDlgItem(IDC_BUTTON_CLEAR)->EnableWindow(bEnable);
  1024.     GetDlgItem(IDC_BUTTON_FILE)->EnableWindow(bEnable);
  1025. }
  1026.  
  1027. HRESULT CPlayDMODlg::ConnectDMOsToRenderer() 
  1028. {
  1029.     USES_CONVERSION;
  1030.     HRESULT hr=0;
  1031.     IPin *pInputPin=0, *pUpstreamOutputPin=0;
  1032.     IBaseFilter *pRenderer=0;
  1033.  
  1034.     // Make sure that the graph is stopped before manipulating its filters
  1035.     hr = m_pMC->Stop();
  1036.  
  1037.     // Find the audio renderer in the graph
  1038. #if 0
  1039.     // It's not recommended to search for Microsoft-provided filters by text
  1040.     // name, since the name could change in the future.  Instead, use 
  1041.     // the more reliable method outlined below.
  1042.     WCHAR wszFilter[64];
  1043.  
  1044.     wcscpy(wszFilter, T2W(TEXT("Default DirectSound Device")));
  1045.     hr = m_pGB->FindFilterByName(wszFilter, &pRenderer);   
  1046.     if (FAILED(hr))
  1047.     {
  1048.         RetailOutput(TEXT("Failed to find audio renderer!\r\n"));
  1049.         goto err;
  1050.     }
  1051. #else
  1052.     //
  1053.     // Enumerate ALL filters in the graph, find one that has one input and 
  1054.     // no outputs, and check to see if it is configured to receive audio data.
  1055.     //
  1056.     hr = FindAudioRenderer(m_pGB, &pRenderer);
  1057.     if (FAILED(hr))
  1058.     {
  1059.         RetailOutput(TEXT("Failed to find audio renderer!\r\n"));
  1060.         goto err;
  1061.     }
  1062. #endif
  1063.  
  1064.     // Verify that an audio renderer is present
  1065.     if (!pRenderer)
  1066.     {
  1067.         MessageBox(TEXT("This file contains no audio component.\r\n\r\n")
  1068.                    TEXT("Please select an audio file or a video file with audio."),
  1069.                    TEXT("No audio renderer!"));
  1070.         goto err;
  1071.     }
  1072.  
  1073.     // Get the pin interface for its input pin
  1074.     hr = GetPin(pRenderer, PINDIR_INPUT, 0, &pInputPin);
  1075.     if (FAILED(hr))
  1076.     {
  1077.         RetailOutput(TEXT("Failed to find audio input pin!\r\n"));
  1078.         goto err;
  1079.     }
  1080.  
  1081.     // Find its upstream connection
  1082.     hr = pInputPin->ConnectedTo(&pUpstreamOutputPin);
  1083.     if (FAILED(hr))
  1084.     {
  1085.         RetailOutput(TEXT("Failed to find audio renderer upstream output pin!\r\n"));
  1086.         goto err;
  1087.     }
  1088.  
  1089.     // Break the connection between these pins
  1090.     hr = pUpstreamOutputPin->Disconnect();
  1091.     if (FAILED(hr))
  1092.     {
  1093.         RetailOutput(TEXT("Failed to disconnect upstream output pin!\r\n"));
  1094.         goto err;
  1095.     }
  1096.     hr = pInputPin->Disconnect();
  1097.     if (FAILED(hr))
  1098.     {
  1099.         RetailOutput(TEXT("Failed to disconnect renderer input pin!\r\n"));
  1100.         goto err;
  1101.     }
  1102.  
  1103.     // Render the upstream filter's output pin again.  This will cause
  1104.     // the filter graph manager to connect our newly loaded DMOs into
  1105.     // the renderer's input pin.
  1106.     hr = m_pGB->Render(pUpstreamOutputPin);
  1107.     if (FAILED(hr))
  1108.     {
  1109.         RetailOutput(TEXT("Failed to render upstream output pin!\r\n"));
  1110.         goto err;
  1111.     }
  1112.  
  1113. err:
  1114.     SAFE_RELEASE(pInputPin);
  1115.     SAFE_RELEASE(pUpstreamOutputPin);
  1116.     SAFE_RELEASE(pRenderer);
  1117.  
  1118.     return hr;
  1119. }
  1120.  
  1121.  
  1122. BOOL CPlayDMODlg::OnEraseBkgnd(CDC *pDC)
  1123. {
  1124.     // Intercept background erasing for the movie window, since the
  1125.     // video renderer will keep the screen painted.  Without this code,
  1126.     // your video window might get painted over with gray (the default
  1127.     // background brush) when it is obscured by another window and redrawn.
  1128.     CRect rc;
  1129.  
  1130.     // Get the bounding rectangle for the movie screen
  1131.     m_Screen.GetWindowRect(&rc);
  1132.     ScreenToClient(&rc);
  1133.  
  1134.     // Exclude the clipping region occupied by our movie screen
  1135.     pDC->ExcludeClipRect(&rc);
  1136.     
  1137.     // Erase the remainder of the dialog as usual
  1138.     return CDialog::OnEraseBkgnd(pDC);
  1139. }
  1140.